#ifndef __SHARED__

#define __SHARED__

struct shared_base {
	
	private:
		
	shared_base() {}
		
	public:
		
	unsigned counter;
	
	shared_base(unsigned c) : counter(c) {}
		
	virtual ~shared_base() {}
	
};

template <typename V>
struct shared_base_impl : public shared_base {
	V * ptr;
	
	private:
		
	shared_base_impl() {}
		
	public:
		
	shared_base_impl(V * p) : shared_base(1), ptr(p) {}
		
	~shared_base_impl() {
		delete ptr;
	}
};

template <typename T>
class shared_ptr;

template <typename T>
void swap(shared_ptr<T> & sp1, shared_ptr<T> & sp2);

template <typename T>
struct shared_ptr {
	shared_base * base;
	T * ptr;	
	
	shared_ptr() {}
	
	public:
	template<typename V>
	shared_ptr(V * p) : base(new shared_base_impl<V>(p)), ptr(static_cast<T *>(p)) {}

	shared_ptr(shared_ptr const & sp) : base(sp . base), ptr(sp . ptr) {
		++ base->counter;
	}
		
	template<typename V>
	shared_ptr(shared_ptr<V> const & sp) : base(sp . base), ptr(static_cast<T *>(sp . ptr)) {
		++ base->counter;
	}
	
	~shared_ptr() {
		if ((-- base->counter) == 0)
			delete base;
	}
	
	friend void swap<>(shared_ptr &, shared_ptr &);
	
	shared_ptr & operator=(shared_ptr const & sp) {
		cout << "operator=" << endl;
		shared_ptr temp(sp);
		swap(temp, *this);
		return *this;
	}

	
	template<typename V>
	shared_ptr<T> & operator=(shared_ptr<V> const & sp) {
		cout << "operator=" << endl;
		shared_ptr<T> temp(sp);
		swap(temp, *this);
		return *this;
	}
	
	T & operator*() {
		return *ptr;
	}
	
	T * operator->() {
		return ptr;
	}
		
};

template <typename T>
void swap(shared_ptr<T> & sp1, shared_ptr<T> & sp2) {
	std::swap(sp1 . ptr, sp2 . ptr);
	std::swap(sp1 . base, sp2 . base);
}

#endif